package colibri;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

public class Fonts {
    public static final int ARIAL_BOLD_11_BLACK = 0;
    public static final int ARIAL_BOLD_11_WHITE = 1;
    public static final int ANONYMOUS_PLAIN_8_BLACK = 10;
    public static final int ANONYMOUS_PLAIN_8_GRAY = 11;
    public static final int ANONYMOUS_PLAIN_8_WHITE = 12;
    public static final int ANONYMOUS_PLAIN_10_BLACK = 13;
    public static final int ANONYMOUS_PLAIN_10_GRAY = 14;
    public static final int ANONYMOUS_PLAIN_10_WHITE = 15;
    private int tipoFont = 0;
    private int baseline;
    private int height;
    private int width;
    private Image imFont;

    private final int[] arialBold11 = new int[] {
        //Primeiros 32 caracteres
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        //Espaço
        3,
        //15 símbolos seguintes (!"#$%&'()*+,-./)
        4, 5, 6, 6, 10, 8, 3, 4, 4, 4, 7, 3, 4, 3, 3,
        //Números de 0 a 9
        6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
        //7 símbolo seguintes (:;<=>?@)
        4, 4, 7, 7, 7, 7, 11,
        //Alfabeto em maiúsculo
        8, 8, 8, 8, 7, 7, 9, 8, 3, 6, 8, 7, 9, 8, 9, 7,
        9, 8, 7, 7, 8, 7, 11, 7, 7, 7,
        //6 símbolos seguintes ([\]^_`)
        4, 3, 4, 7, 6, 4,
        //Alfabeto em minúsculo
        6, 7, 6, 7, 6, 4, 7, 7, 3, 3, 6, 3, 10, 7, 7, 7,
        7, 4, 6, 4, 7, 6, 9, 6, 6, 6,
        //4 símbolos seguintes ({|}~)
        4, 3, 4, 7,
        //Símbolo do DELETE (X)
        7,
        //33 caracteres seguintes
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        3,
        //31 símbolos seguintes (¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿)
        4, 6, 6, 6, 6, 3, 6, 4, 8, 4, 6, 7, 4, 8, 6, 5,
        6, 4, 4, 4, 6, 6, 3, 4, 4, 4, 6, 9, 9, 9, 7,
        //32 símbolos e vogais em maiúsculo acentuadas (ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß)
        8, 8, 8, 8, 8, 8, 11, 8, 7, 7, 7, 7, 3, 3, 3, 3,
        8, 8, 9, 9, 9, 9,  9, 7, 9, 8, 8, 8, 8, 7, 7, 7,
        //32 símbolos e vogais em minúsculo acentuadas (àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ)
        6, 6, 6, 6, 6, 6, 10, 6, 6, 6, 6, 6, 3, 3, 3, 3,
        7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 6, 7, 6
    };

    private final int[] anonymousPlain8 = new int[] {
        //Primeiros 32 caracteres
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //Espaço
        5,
        //15 símbolos seguintes (!"#$%&'()*+,-./)
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //Números de 0 a 9
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //7 símbolo seguintes (:;<=>?@)
        5, 5, 5, 5, 5, 5, 5,
        //Alfabeto em maiúsculo
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //6 símbolos seguintes ([\]^_`)
        5, 5, 5, 5, 5, 5,
        //Alfabeto em minúsculo
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //4 símbolos seguintes ({|}~)
        5, 5, 5, 5,
        //Símbolo do DELETE (X)
        5,
        //33 caracteres seguintes
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5,
        //31 símbolos seguintes (¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿)
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //32 símbolos e vogais em maiúsculo acentuadas (ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß)
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        //32 símbolos e vogais em minúsculo acentuadas (àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ)
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
    };

    private final int[] anonymousPlain10 = new int[] {
        //Primeiros 32 caracteres
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //Espaço
        7,
        //15 símbolos seguintes (!"#$%&'()*+,-./)
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //Números de 0 a 9
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //7 símbolo seguintes (:;<=>?@)
        7, 7, 7, 7, 7, 7, 7,
        //Alfabeto em maiúsculo
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //6 símbolos seguintes ([\]^_`)
        7, 7, 7, 7, 7, 7,
        //Alfabeto em minúsculo
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //4 símbolos seguintes ({|}~)
        7, 7, 7, 7,
        //Símbolo do DELETE (X)
        7,
        //33 caracteres seguintes
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7,
        //31 símbolos seguintes (¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿)
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //32 símbolos e vogais em maiúsculo acentuadas (ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß)
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        //32 símbolos e vogais em minúsculo acentuadas (àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ)
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    };

    public Fonts (int tipoFont) {
        this.tipoFont = tipoFont;
        try {
            switch (tipoFont) {
                case 0:
                    imFont = Image.createImage("/res/fonts/arial_bold_11_black.png");
                    break;
                case 1:
                    imFont = Image.createImage("/res/fonts/arial_bold_11_white.png");
                    break;
                case 10:
                    imFont = Image.createImage("/res/fonts/anonymous_plain_8_black.png");
                    break;
                case 11:
                    imFont = Image.createImage("/res/fonts/anonymous_plain_8_gray.png");
                    break;
                case 12:
                    imFont = Image.createImage("/res/fonts/anonymous_plain_8_white.png");
                    break;
                case 13:
                    imFont = Image.createImage("/res/fonts/anonymous_plain_10_black.png");
                    break;
                case 14:
                    imFont = Image.createImage("/res/fonts/anonymous_plain_10_gray.png");
                    break;
                case 15:
                    imFont = Image.createImage("/res/fonts/anonymous_plain_10_white.png");
                    break;
            }
            height = imFont.getHeight();
            width  = imFont.getWidth()/252;
            baseline = calculateBaseline();
        } catch (Exception e) {
            e.printStackTrace();
            throw new NullPointerException("Colibri error: Falha ao carregar fonte: " + e.getMessage());
        }
    }

    private int calculateBaseline(){
        // get baseline: defaults to last row
        int result = height;
        int imageWidth = imFont.getWidth();
        int max = 0;
        int total;
        int[] row = new int[ imageWidth ];
        int background;

        // determine background color: assume it's at 0, 0
        imFont.getRGB( row, 0, 1, 0, 0, 1, 1 );
        background = row[0];

        // here's the heuristic: find the row on the bottom
        // half of the image with the most non-background pixels
        for ( int y = height/2; y < height; y++ ){
            total = 0;
            imFont.getRGB( row, 0, imageWidth, 0, y, imageWidth, 1 );
            for ( int x = 0; x < imageWidth; x++ ){
                if ( row[x] != background ) total++;
            }
            if ( total > max ){
                max = total;
                result = y;
            }
        }

        return result;
    }

    public int charsWidth( char[] ch, int offset, int length ){
        int w = 0;
        for ( int i = 0; i < length; i++ ){
            switch (tipoFont) {
                case 0:
                case 1:
                    w += arialBold11[(int)ch[i]];
                    break;
                case 10:
                case 11:
                case 12:
                    w += anonymousPlain8[(int)ch[i]];
                    break;
                case 13:
                case 14:
                case 15:
                    w += anonymousPlain10[(int)ch[i]];
                    break;
            }
        }
        return w;
    }

    public int charWidth( char ch ){
        return width;
    }

    public int getBaselinePosition(){
        return baseline;
    }

    public int getHeight(){
        return height;
    }

    public int stringWidth( String str ){
        return charsWidth( str.toCharArray(), 0, str.length() );
    }

    public int substringWidth( String str, int offset, int len ){
        return charsWidth( str.toCharArray(), offset, len );
    }

    /**
    * Paints the specified character at the specified coordinates
    * on the Graphics instance using Graphics' anchoring constants.
    */
    public void drawChar( Graphics g, char character, int x, int y, int anchor ){
        int clipX = g.getClipX();
        int clipY = g.getClipY();
        int clipW = g.getClipWidth();
        int clipH = g.getClipHeight();

        drawCharInternal( g, character, x, y, anchor );

        g.setClip( clipX, clipY, clipW, clipH );
    }


    /**
    * Paints the characters as specified.
    */
    public void drawChars( Graphics g, char[] data, int offset, int length, int x, int y, int anchor ){
        if ( (anchor & Graphics.RIGHT) != 0 ){
            x -= charsWidth( data, offset, length );
        }else if ( (anchor & Graphics.HCENTER) != 0 ){
            x -= ( charsWidth( data, offset, length ) / 2 );
        }

        if ( (anchor & Graphics.BOTTOM) != 0 ){
            y -= height;
        }else if ( (anchor & Graphics.VCENTER) != 0 ){
            y -= height/2;
        }

        int clipX = g.getClipX();
        int clipY = g.getClipY();
        int clipW = g.getClipWidth();
        int clipH = g.getClipHeight();

        char c;
        for ( int i = 0; i < length; i++ ){
            c = data[offset+i];
            drawCharInternal( g, c, x, y, Graphics.TOP|Graphics.LEFT );

            switch (tipoFont) {
                case 0:
                case 1:
                    x += arialBold11[(int)c];
                    break;
                case 10:
                case 11:
                case 12:
                    x += anonymousPlain8[(int)c];
                    break;
                case 13:
                case 14:
                case 15:
                    x += anonymousPlain10[(int)c];
                    break;
            }
        }

        g.setClip( clipX, clipY, clipW, clipH );
    }

    /**
    * Draws the actual characters without worrying about
    * saving and restoring the existing clip region.
    */
    private void drawCharInternal( Graphics g, char character, int x, int y, int anchor ){
            switch (tipoFont) {
                case 0:
                case 1:
                    width = arialBold11[(int)character];
                    break;
                case 10:
                case 11:
                case 12:
                    width = anonymousPlain8[(int)character];
                    break;
                case 13:
                case 14:
                case 15:
                    width = anonymousPlain10[(int)character];
                    break;
            }
            g.setClip( x, y, width, height );

            width = 0;
            for (int i = 0; i < (int)character; i++) {
                switch (tipoFont) {
                case 0:
                case 1:
                    width += arialBold11[i];
                    break;
                case 10:
                case 11:
                case 12:
                    width += anonymousPlain8[i];
                    break;
                case 13:
                case 14:
                case 15:
                    width += anonymousPlain10[i];
                    break;
                }
            }

            g.drawImage( imFont, x-width, y, anchor );
    }

    /**
    * Paints the string as specified.
    */
    public void drawString( Graphics g, String str, int x, int y, int anchor ){
        drawChars( g, str.toCharArray(), 0, str.length(), x, y, anchor );
    }

    /**
    * Paints the substring as specified.
    */
    public void drawSubstring( Graphics g, String str, int offset, int len, int x, int y, int anchor ){
        drawChars( g, str.toCharArray(), offset, len, x, y, anchor );
    }
}